﻿using System;
using System.Collections;
using System.ComponentModel;

namespace UIT.ScrumTool.Client.Utilities.TaskGridView
{
    public class TaskBindingListComplete : CollectionBase, IBindingList, ITypedList, ISupportInitialize
    {
        public int m_initCounter;
        public TaskEditTable m_lastAddedComposer;

        #region Implementation for the typed collection

        // Add a composer to the collection.  Used to fill the collection.

        public TaskEditTable this[int index]
        {
            get { return (TaskEditTable) List[index]; }
            set { List[index] = value; }
        }

        public void Add(TaskEditTable composer)
        {
            List.Add(composer);
        }

        protected override void OnValidate(object value)
        {
            // Check to make sure that the element is not null
            base.OnValidate(value);

            // Check to make sure that the element is a ComposerEditable object
            if (!(value is TaskEditTable))
                throw new ArgumentException("Only ComposerEditable objects can be added to the collection");
        }

        #endregion Implementation for the typed collection

        #region Implementation of IBindingList

        // Return a new ComposerEditable object already added to the collection.
        // The grid will use it to insert a new row.
        public object AddNew()
        {
            // Create a new ComposerEditable object
            var composer = new TaskEditTable();

            // Put the composer into a state where calling CancelEdit will remove the composer from the collection.
            composer.BeginEdit();

            // Add the composer to the collection.
            Add(composer);

            // Keep track of the last composer added via AddNew.
            m_lastAddedComposer = composer;

            return composer;
        }

        // To tell that we support the AddNew method.
        public bool AllowNew
        {
            get { return true; }
        }

        // To tell that we support the removal of elements.
        public bool AllowRemove
        {
            get { return true; }
        }

        // To tell that we support the modification of elements.
        public bool AllowEdit
        {
            get { return true; }
        }

        // Since the grid will take care of sorting the data rows
        // we do not need to enable sorting in the collection.
        public bool SupportsSorting
        {
            get { return false; }
        }

        // Since the grid does not need to search, we do not need
        // to enable searching in the collection.
        public bool SupportsSearching
        {
            get { return false; }
        }

        // To tell that we will raise the ListChanged event.
        public bool SupportsChangeNotification
        {
            get { return true; }
        }

        // Since the grid does not need to search, we do not need
        // to enable searching in the collection.
        public void AddIndex(PropertyDescriptor property)
        {
            throw new NotSupportedException();
        }

        // Since the grid will take care of sorting the data rows
        // we do not need to enable sorting in the collection.
        public void ApplySort(PropertyDescriptor property, ListSortDirection direction)
        {
            throw new NotSupportedException();
        }

        // Since the grid does not need to search, we do not need
        // to enable searching in the collection.
        public int Find(PropertyDescriptor property, object key)
        {
            throw new NotSupportedException();
        }

        // Since the grid will take care of sorting the data rows
        // we do not need to enable sorting in the collection.
        public void RemoveSort()
        {
            throw new NotSupportedException();
        }

        // Since the grid does not need to search, we do not need
        // to enable searching in the collection.
        public void RemoveIndex(PropertyDescriptor property)
        {
            throw new NotSupportedException();
        }

        // Since the grid will take care of sorting the data rows
        // we do not need to enable sorting in the collection.
        public PropertyDescriptor SortProperty
        {
            get { throw new NotSupportedException(); }
        }

        // Since the grid will take care of sorting the data rows
        // we do not need to enable sorting in the collection.
        public bool IsSorted
        {
            get { throw new NotSupportedException(); }
        }

        // Since the grid will take care of sorting the data rows
        // we do not need to enable sorting in the collection.
        public ListSortDirection SortDirection
        {
            get { throw new NotSupportedException(); }
        }

        public event ListChangedEventHandler ListChanged;

        // Raise the ListChanged event to advise the grid of any changes.
        protected virtual void OnListChanged(ListChangedEventArgs e)
        {
            try
            {
                if (ListChanged != null)
                    ListChanged(this, e);
            }
            catch
            {
            }
        }

        protected override void OnRemoveComplete(int index, object value)
        {
            ((TaskEditTable) value).m_containingList = null;

            // Advise the grid that a row has been removed.
            InvokeOnListChanged(new ListChangedEventArgs(ListChangedType.ItemDeleted, index));
        }

        protected override void OnInsert(int index, object value)
        {
            // Commit the previously pending AddNew.
            if (m_lastAddedComposer != null)
            {
                m_lastAddedComposer.EndEdit();
                m_lastAddedComposer = null;
            }
        }

        protected override void OnInsertComplete(int index, object value)
        {
            ((TaskEditTable) value).m_containingList = this;

            // Advise the grid that a new row has been inserted.
            InvokeOnListChanged(new ListChangedEventArgs(ListChangedType.ItemAdded, index));
        }

        protected override void OnClearComplete()
        {
            // Advise the grid that the collection has been reset.
            InvokeOnListChanged(new ListChangedEventArgs(ListChangedType.Reset, -1, -1));
        }

        protected override void OnClear()
        {
            foreach (TaskEditTable composer in this)
            {
                composer.m_containingList = null;
            }
        }

        protected override void OnSetComplete(int index, object oldValue, object newValue)
        {
            if (oldValue == newValue)
                return;

            // We do not check if the old and new values are null since it is impossible.      
            ((TaskEditTable) oldValue).m_containingList = null;
            ((TaskEditTable) newValue).m_containingList = this;

            InvokeOnListChanged(new ListChangedEventArgs(ListChangedType.ItemChanged, index));
        }

        #endregion Implementation of IBindingList

        #region Implementation of ITypedList

        public PropertyDescriptorCollection GetItemProperties(PropertyDescriptor[] properties)
        {
            // We sort the property descriptor to have the columns in our grid in that order by default.
            PropertyDescriptorCollection original = TypeDescriptor.GetProperties(typeof (TaskEditTable));
            var sorted = new PropertyDescriptorCollection(null);

            sorted.Add(original["ID"]);
            sorted.Add(original["Subject"]);
            sorted.Add(original["Description"]);
            sorted.Add(original["EstimateStoryPoint"]);
            sorted.Add(original["Importance"]);
            sorted.Add(original["OperatorId"]);
            sorted.Add(original["SprintId"]);
            sorted.Add(original["ProjectId"]);
            sorted.Add(original["Height"]);
            sorted.Add(original["Color"]);
            sorted.Add(original["EstimatedDuration"]);
            return sorted;
        }

        public string GetListName(PropertyDescriptor[] listAccessors)
        {
            return GetType().Name;
        }

        #endregion Implementation of ITypedList

        #region Implementation of ISupportInitialize

        // Indicates if we are in batch initialization.
        public bool InBatchInitialization
        {
            get { return m_initCounter > 0; }
        }

        // Begins the batch initialization.
        public void BeginInit()
        {
            m_initCounter++;
        }

        // Ends the batch initialization.
        public void EndInit()
        {
            if (m_initCounter > 0)
            {
                m_initCounter--;

                if (m_initCounter == 0)
                    OnListChanged(new ListChangedEventArgs(ListChangedType.Reset, -1, -1));
            }
        }

        #endregion Implementation of ISupportInitialize

        internal TaskEditTable LastAddedComposer
        {
            get { return m_lastAddedComposer; }
            set { m_lastAddedComposer = value; }
        }

        internal void InvokeOnListChanged(ListChangedEventArgs e)
        {
            // Prevents the raise of the ListChanged event if we are in batch initialisation.
            if (!InBatchInitialization)
                OnListChanged(e);
        }
    }
}